﻿using System.Text;
namespace client35 {
	using Autofac;
	using client35.json;
	using client35.socket.json;
	using common;
	using i_core;
	using i_core.net;
	using i_core.p_enum;
	using i_core.usr;
	using Newtonsoft.Json;
	using System;
	using System.Collections.Generic;
	using System.Reactive.Concurrency;
	using System.Reactive.Linq;
	using System.Threading;
	using System.Threading.Tasks;

	public class json_socket : observable_socket, i_connect {

		public e_connect_type type => e_connect_type.socket;

		public new bool is_connected => base.is_connected;

		public string svr_ip { get; set; }

		public int svr_port { get; set; }

		public string local_ip { get; set; }

		public int local_port { get; set; }

		public int lx_report_queue { get; set; }

		public i_log log { get; set; }

		public IObservable<i_r_login_info> login_event => _messages
					.Select(builder => JsonConvert.DeserializeObject<r_skt_login_info>(builder))
					.Where(w => w.header.type == e_skt_type.login)
					.AsObservable();

		public IObservable<i_r_skt_ka_info> recording_event => _messages
					.Select(builder => JsonConvert.DeserializeObject<r_skt_recording_info>(builder))
					.Where(w => w.header.type == e_skt_type.recording)
					.AsObservable();

		public IObservable<i_r_answer_info> answer_event => _messages
					.Select(builder => JsonConvert.DeserializeObject<r_skt_answer_info>(builder))
					.Where(w => w.header.type == e_skt_type.answer)
					.AsObservable();

		public IObservable<i_r_terminate_info> terminate_event => _messages
					.Select(builder => JsonConvert.DeserializeObject<r_skt_terminate_info>(builder))
					.Where(w => w.header.type == e_skt_type.terminate)
					.AsObservable();
		public IObservable<i_r_exit_info> exit_event => _messages
					.Select(builder => JsonConvert.DeserializeObject<r_skt_exit_info>(builder))
					.Where(w => w.header.type == e_skt_type.exit)
					.AsObservable();

		public IObservable<i_r_skt_ka_info> skt_ka_event => _messages
					.Select(builder => JsonConvert.DeserializeObject<r_skt_skt_ka_info>(builder))
					.Where(w => w.header.type == e_skt_type.skt_ka)
					.AsObservable();

		public IObservable<i_r_call_info> skt_call_event => _messages
					.Select(builder => JsonConvert.DeserializeObject<r_skt_call_info>(builder))
					.Where(w => w.header.type == e_skt_type.call)
					.AsObservable();

		public json_socket() { }

		/// <summary>
		/// Instantiates an <see cref="json_socket"/> instance wrapping the provided
		/// </summary>
		public json_socket(string svr_ip, int svr_port, string local_ip, int local_port) : base(svr_ip, svr_port, local_ip, local_port) {
			log = global_vars.scope.ResolveKeyed<i_log>(log_type.log4net,
				new NamedParameter("user", "system"),
				new NamedParameter("islog", true));
		}

		public i_login_info p_login_info(i_user_info user_info) {
			var u_info = user_info as base_user_info;
			return new skt_login_info {
				header = new skt_header() { type = e_skt_type.login, uid = Guid.NewGuid().ToString() },
				id = u_info.id.ToString(),
				isback = "",
				mac = "",
				name = u_info.user_name,
				unique_id = u_info.unique_id
			};
		}



		public i_dial_info p_dial_info(i_user_info user_info, string local_number, string remote_number) {
			var u_info = user_info as base_user_info;
			return new skt_dial_info {
				header = new skt_header() {
					type = e_skt_type.dial,
					uid = Guid.NewGuid().ToString()
				},
				keys = null,
				local_number = local_number,
				remote_number = remote_number
			};
		}


		public i_terminate_info p_terminate_info(i_user_info user_info, string cause) {
			var u_info = user_info as base_user_info;
			return new skt_terminate_info {
				header = new skt_header() {
					type = e_skt_type.terminate,
					uid = Guid.NewGuid().ToString()
				},
				keys = null,
				cause = cause
			};
		}


		public i_exit_info p_exit_info(i_user_info user_info, string cause) {
			var u_info = user_info as base_user_info;
			return new skt_exit_info {
				header = new skt_header() {
					type = e_skt_type.exit,
					uid = Guid.NewGuid().ToString()
				},
				keys = null,
			};
		}
		public async Task<bool> send_message_info(string message) {
			var task_source = new TaskCompletionSource<bool>();
			try {
				await SendAsync(message);
				task_source.TrySetResult(true);
			} catch (Exception ex) {
				log.Error($"send message error", ex);
				task_source.TrySetResult(false);
			}
			return await task_source.Task;
		}

		public async Task<bool> send_message_info<T>(T message_info) where T : i_skt_info {
			var task_source = new TaskCompletionSource<bool>();
			var cancel_source = new CancellationTokenSource();
			cancel_source.Token.Register(() => {
				task_source.TrySetResult(false);
			});

			var message = JsonConvert.SerializeObject(message_info);
			log.Debug($"send message:\r\n{message}");
			await SendAsync(message);
			task_source.TrySetResult(true);
			return await task_source.Task;
		}

		~json_socket() { }
		protected override void Dispose(bool disposing) {
			base.Dispose(disposing);
		}
	}
}
